home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
DJGPP
/
DJSRC111.ZIP
/
go32
/
paging.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-12-05
|
35KB
|
1,245 lines
/* This is file PAGING.C */
/*
** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
**
** This file is distributed under the terms listed in the document
** "copying.dj", available from DJ Delorie at the address above.
** A copy of "copying.dj" should accompany this file; if not, a copy
** should be available from where this file was obtained. This file
** may not be distributed without a verbatim copy of "copying.dj".
**
** This file is distributed WITHOUT ANY WARRANTY; without even the implied
** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
/* Modified for VCPI Implement by Y.Shibata Aug 5th 1991 */
/* Modified for DPMI Implement by H.Tsubakimoto */
/* NUR paging algorithm by rcharif@math.utexas.edu */
/* Merged DPMI with V1.09+ code C. Sandmann sandmann@clio.rice.edu */
#include <stdio.h>
#include <dos.h>
#include <fcntl.h>
#include <io.h>
#include <sys/stat.h>
#include <bios.h>
#include <string.h>
#include <stdlib.h>
#include "gotypes.h"
#include "paging.h"
#include "graphics.h"
#include "tss.h"
#include "idt.h"
#include "gdt.h"
#include "valloc.h"
#include "dalloc.h"
#include "utils.h"
#include "aout.h"
#include "mono.h"
#include "vcpi.h"
#include "dpmi.h"
#include "extdebug.h"
#include "exphdlr.h"
#include "stubinfo.h"
#include "proginfo.h"
#include "control.h"
#define VERBOSE 0
/* #define KEEP_ON_EXEC */
#define MAX_PAGING_NUM 2
#define DOS_PAGE 256 /* 1MB / 4KB = 256 Pages */
extern char transfer_buffer[4096];
extern word32 ptr2linear(void far *ptr);
struct {
word16 limit;
word32 base;
} gdt_phys, idt_phys;
CLIENT client; /* VCPI Change Mode Structure */
word32 abs_client; /* _DS * 16L + &client */
far32 vcpi_entry;
SYS_TBL int_descriptor;
SYS_TBL gbl_descriptor;
extern word16 vcpi_installed; /* VCPI Installed Flag */
extern near protect_entry();
word32 DPMI_STACK = 0x40000L; /* 256Kb Min */
#define DPMIgetpage 0xffffL /* 64K instead of 4K for speed */
DPMImemory DPMImem; /* protected memory block */
static word32 oldbase; /* DPMI selector base for allocated memory */
static word16 DPMIselect; /* selectors for application */
/* DPMIselect + 0 : data selector */
/* DPMIselect + 8 : code selector */
/* DPMIselect + 16 : stack selector */
/* DPMIselect + 24 : linear 1Mb range */
extern TSS *utils_tss;
extern int debug_mode;
extern word32 mem_avail;
extern int self_contained;
extern long header_offset;
word16 core_selector, arena_ds, arena_cs;
AREAS areas[MAX_AREA];
#if VERBOSE
static char *aname[MAX_AREA] = {
"text ",
"data ",
"bss ",
"arena",
"stack",
"vga ",
"syms ",
"syms2",
"emu"
};
#endif
static char achar[MAX_AREA] = "tdbmsg?e";
word32 far *pd = 0;
word8 pd_seg[1024];
word32 far *vcpi_pt = 0;
word8 paging_buffer[4096*MAX_PAGING_NUM];
word32 screen_primary, screen_secondary;
word32 ptr2linear(void far *ptr)
{
return (word32)FP_SEG(ptr) * 16L + (word32)FP_OFF(ptr);
}
static word32 far2pte(void far *ptr, word32 flags)
{
return (vcpi_pt[(int)(((word32)ptr) >> 24)] & 0xfffff000L) | flags;
}
static word32 pn2pte(unsigned pn, word32 flags)
{
return (vcpi_pt[pn] & 0xfffff000L) | flags;
}
static void setDPMISelectors(int firsttime)
{
int selfail;
selfail = 0;
if(!DPMIassignSelector(DPMIselect, 0xc0b3, DPMImem.address,
DPMImem.bytes - 1 ) ) selfail = 1; /* win 3.1 needs f, 3.0 b */
if(firsttime){
if(!DPMIassignSelector(DPMIselect + 8, 0xc0bb, DPMImem.address,
DPMImem.bytes - 1) ) selfail |= 2;
if(!DPMIassignSelector(DPMIselect + 16, 0xc0b7, DPMImem.address,
(areas[A_stack].first_addr - 1) ) ) selfail |= 4;
} else if(DPMImem.address != oldbase) {
if(!DPMISelectorBase(DPMIselect + 8, DPMImem.address) ) selfail |= 10;
if(!DPMISelectorBase(DPMIselect + 16, DPMImem.address) ) selfail |= 12;
if(using_external_debugger) {
DPMIrealMode();
clear_break_DPMI(); /* This clears the breakpoints */
set_break_DPMI(); /* This resets them with new base */
DPMIprotectedMode();
}
}
oldbase = DPMImem.address;
#if VERBOSE
if(selfail) {
/* For some reason stack #4 fails under OS2 but it still works; thus
the workaround is to ignore this section unless in verbose mode */
DPMIrealMode();
fprintf(stderr,"DPMI: AssignSelector %d failed!\n",selfail);
/* exit(3); */
DPMIprotectedMode(); /* Only if exit commented */
}
#endif
}
void loadAout(const AREAS* areas)
{
word32 count = areas->last_addr + 1 - areas->first_addr;
if (count > 0) {
word32 loadAddr = areas->first_addr;
lseek(areas->fileno, areas->foffset, 0);
while (count > 0) {
word16 readBytes;
word16 bytes = (count > 4096) ? 4096 : (word16)count;
readBytes = read(areas->fileno, transfer_buffer, bytes);
if (readBytes < bytes) memset(transfer_buffer + readBytes, 0, bytes - readBytes);
memput(loadAddr, transfer_buffer, bytes);
loadAddr += bytes;
count -= bytes;
}
}
}
void clearDPMIstate(void)
{
DPMIfree(&DPMImem); /* QDPMI bug fix - child processes don't free memory */
}
static void saveDPMIstate(void)
{
int a;
word32 firsta, lengtha;
word16 bytes;
unsigned block;
block = 0;
for (a=0; a<MAX_AREA; a++) {
firsta = areas[a].first_addr;
if ( a == A_stack ) firsta = a_tss.tss_esp & 0xfffff000L;
lengtha = areas[a].last_addr - firsta + 1;
while (lengtha > 0) {
bytes = (lengtha > 4096) ? 4096 : (word16)lengtha;
Pmemget(DPMIselect, firsta, paging_buffer, bytes);
dwrite(paging_buffer, block++);
firsta += bytes;
lengtha -= bytes;
}
}
DPMIprotectedMode();
DPMIfree(&DPMImem);
restoreDPMIvector();
DPMIrealMode();
}
static void restoreDPMIstate(void)
{
int a;
word32 firsta, lengtha;
word16 bytes;
unsigned block;
DPMIprotectedMode();
setDPMIvector();
lengtha = (areas[A_arena].last_addr + 1 + DPMIgetpage) & ~DPMIgetpage;
if (! DPMIalloc(&DPMImem, lengtha)) {
DPMIrealMode();
fprintf(stderr,"\nDPMI: Not enough memory (0x%08lx bytes).\n", lengtha);
exit(3);
}
setDPMISelectors(0);
DPMIrealMode();
firsta = areas[A_arena].last_addr + 1;
if(lengtha > firsta)
Pmemset(DPMIselect, firsta, 0, lengtha - firsta );
block = 0;
for (a=0; a<MAX_AREA; a++) {
firsta = areas[a].first_addr;
if ( a == A_stack ) firsta = a_tss.tss_esp & 0xfffff000L;
lengtha = areas[a].last_addr - firsta + 1;
while (lengtha > 0) {
bytes = (lengtha > 4096) ? 4096 : (word16)lengtha;
dread(paging_buffer, block++);
Pmemput(DPMIselect, firsta, paging_buffer, bytes);
firsta += bytes;
lengtha -= bytes;
}
}
}
int changeBreak(word32 breakPoint)
{
word32 oldbytes, newbytes;
newbytes = (breakPoint + DPMIgetpage) & ~DPMIgetpage; /* 64K for performance */
oldbytes = DPMImem.bytes;
if (newbytes < areas[A_arena].first_addr) newbytes=areas[A_arena].first_addr;
#if VERBOSE
fprintf(stderr,"changeBreak: old=0x%08lx break=0x%08lx new=0x%08lx\n",
oldbytes, breakPoint, newbytes);
#endif
if (DPMImem.bytes != newbytes) {
DPMIprotectedMode();
if (! DPMIrealloc(&DPMImem, newbytes)) {
DPMIrealMode();
fprintf(stderr,"\nDPMI: Not enough memory (0x%08lx bytes).\n", newbytes);
return 0;
}
setDPMISelectors(0);
DPMIrealMode();
}
if(newbytes > oldbytes)
Pmemset(DPMIselect, oldbytes, 0, newbytes - oldbytes );
return 1;
}
/* VCPI Get Interface */
void link_vcpi(word32 far *dir, word32 far *table)
{
vcpi_entry.selector = g_vcpicode * 8;
vcpi_entry.offset32 = get_interface(table,&gdt[g_vcpicode]);
client.page_table = far2pte(dir, 0); /* (word32)dir>>12; */
client.gdt_address = ptr2linear(&gdt_phys);
client.idt_address = ptr2linear(&idt_phys);
client.ldt_selector = 0;
client.tss_selector = g_ctss * 8;
client.entry_eip = (word16)protect_entry;
client.entry_cs = g_rcode * 8;
abs_client = ptr2linear(&client);
}
void handle_screen_swap(word32 far *pt)
{
struct REGPACK r;
int have_mono=0;
int have_color=0;
int have_graphics=0;
int save, new;
r.r_ax = 0x1200;
r.r_bx = 0xff10;
r.r_cx = 0xffff;
intr(0x10, &r);
if (r.r_cx == 0xffff)
pokeb(0x40, 0x84, 24); /* the only size for CGA/MDA */
if (!vcpi_installed || (pt[0xb8] & (PT_U|PT_W)) == (PT_W|PT_U))
{
save = peekb(screen_seg, 0);
pokeb(screen_seg, 0, ~save);
new = peekb(screen_seg, 0);
pokeb(screen_seg, 0, save);
if (new == ~save)
have_color = 1;
}
if (!vcpi_installed || (pt[0xb0] & (PT_U|PT_W)) == (PT_W|PT_U))
{
save = peekb(0xb000, 0);
pokeb(0xb000, 0, ~save);
new = peekb(0xb000, 0);
pokeb(0xb000, 0, save);
if (new == ~save)
have_mono = 1;
}
r.r_ax = 0x0f00;
intr(0x10, &r);
if ((r.r_ax & 0xff) > 0x07)
have_graphics = 1;
if (have_graphics && have_mono)
have_color = 1;
else if (have_graphics && have_color)
have_mono = 1;
screen_primary = 0xe00b8000L;
screen_secondary = 0xe00b0000L;
if (have_color && !have_mono)
{
screen_secondary = 0xe00b8000L;
return;
}
if (have_mono & !have_color)
{
screen_primary = 0xe00b0000L;
return;
}
if ((biosequip() & 0x0030) == 0x0030) /* mono mode, swap! */
{
screen_primary = 0xe00b0000L;
screen_secondary = 0xe00b8000L;
return;
}
}
void paging_set_file(char *fname)
{
word32 newbytes;
word32 far *pt;
FILEHDR filehdr;
AOUTHDR aouthdr;
SCNHDR scnhdr[3];
GNU_AOUT gnu_aout;
unsigned short *exe_hdr;
int i;
int aout_f;
aout_f = open(fname, O_RDONLY|O_BINARY);
if (aout_f < 0)
{
fprintf(stderr, "Can't open file <%s>\n", fname);
exit(1);
}
areas[A_text].fileno = aout_f;
areas[A_data].fileno = aout_f;
for (i=A_bss; i<A_max; i++)
areas[i].fileno = 0;
if (topline_info)
for (i=0; fname[i]; i++)
poke(screen_seg, i*2+10, fname[i] | 0x0700);
lseek(aout_f, header_offset, 0);
read(aout_f, &filehdr, sizeof(filehdr));
if (filehdr.f_magic == 0x5a4d) /* .EXE */
{
exe_hdr = (unsigned short *)&filehdr;
header_offset += (long)exe_hdr[2]*512L;
if (exe_hdr[1])
header_offset += (long)exe_hdr[1] - 512L;
lseek(aout_f, header_offset, 0);
read(aout_f, &filehdr, sizeof(filehdr));
}
if (filehdr.f_magic != 0x14c)
{
lseek(aout_f, header_offset, 0);
read(aout_f, &gnu_aout, sizeof(gnu_aout));
a_tss.tss_eip = gnu_aout.entry;
aouthdr.tsize = gnu_aout.tsize;
aouthdr.dsize = gnu_aout.dsize;
aouthdr.bsize = gnu_aout.bsize;
}
else
{
read(aout_f, &aouthdr, sizeof(aouthdr));
a_tss.tss_eip = aouthdr.entry;
read(aout_f, scnhdr, sizeof(scnhdr));
}
arena_cs =
a_tss.tss_cs = g_acode*8;
arena_ds =
a_tss.tss_ds =
a_tss.tss_es =
a_tss.tss_fs =
a_tss.tss_ss = g_adata*8;
a_tss.tss_esp = 0x7ffffffcL;
if (filehdr.f_magic == 0x14c)
{
areas[A_text].first_addr = aouthdr.text_start + ARENA;
areas[A_text].foffset = scnhdr[0].s_scnptr + header_offset;
areas[A_text].last_addr = areas[A_text].first_addr + aouthdr.tsize - 1;
}
else if (filehdr.f_magic == 0x10b)
{
areas[A_text].first_addr = ARENA;
if (a_tss.tss_eip >= 0x1000) /* leave space for null reference */
areas[A_text].first_addr += 0x1000; /* to cause seg fault */
areas[A_text].foffset = header_offset;
areas[A_text].last_addr = areas[A_text].first_addr + aouthdr.tsize + 0x20 - 1;
}
else if (debug_mode && filehdr.f_magic == 0x107)
{
struct stat sbuf;
fstat(aout_f, &sbuf);
areas[A_text].first_addr = ARENA;
areas[A_text].foffset = 0x20 + header_offset;
areas[A_text].last_addr = sbuf.st_size + ARENA - 0x20;
}
else if (debug_mode)
{
struct stat sbuf;
fstat(aout_f, &sbuf);
areas[A_text].first_addr = ARENA;
areas[A_text].foffset = header_offset;
areas[A_text].last_addr = sbuf.st_size + ARENA;
}
else
{
fprintf(stderr, "Unknown file type 0x%x (0%o)\n", filehdr.f_magic, filehdr.f_magic);
exit(-1);
}
if (debug_mode)
fprintf(stderr, "%ld+", aouthdr.tsize);
if (filehdr.f_magic == 0x14c)
{
areas[A_data].first_addr = aouthdr.data_start + ARENA;
areas[A_data].foffset = scnhdr[1].s_scnptr + header_offset;
}
else
{
areas[A_data].first_addr = (areas[A_text].last_addr+0x3fffffL)&~0x3fffffL;
areas[A_data].foffset = ((aouthdr.tsize + 0x20 + 0xfffL) & ~0xfffL) + header_offset;
}
areas[A_data].last_addr = areas[A_data].first_addr + aouthdr.dsize - 1;
if (debug_mode)
fprintf(stderr, "%ld+", aouthdr.dsize);
areas[A_bss].first_addr = areas[A_data].last_addr + 1;
areas[A_bss].foffset = -1;
areas[A_bss].last_addr = areas[A_bss].first_addr + aouthdr.bsize - 1;
if (debug_mode)
fprintf(stderr, "%ld = %ld\n", aouthdr.bsize,
aouthdr.tsize+aouthdr.dsize+aouthdr.bsize);
areas[A_arena].first_addr = (areas[A_bss].last_addr + 1 + 7) & ~7L;
areas[A_arena].last_addr = areas[A_arena].first_addr - 1;
areas[A_arena].foffset = -1;
if(!use_DPMI)
{
areas[A_stack].first_addr = 0x50000000L;
areas[A_stack].last_addr = 0x8fffffffL;
areas[A_stack].foffset = -1;
areas[A_vga].first_addr = 0xe0000000L;
areas[A_vga].last_addr = 0xe03fffffL;
areas[A_vga].foffset = -1;
areas[A_syms].first_addr = 0xa0000000L;
areas[A_syms].last_addr = 0xafffffffL;
areas[A_syms].foffset = -1;
pd = (word32 far *)((long)valloc(VA_640) << 24);
vcpi_pt = pt = (word32 far *)((long)valloc(VA_640) << 24);
for (i=0; i<1024; i++)
{
pd[i] = 0;
pd_seg[i] = 0;
}
if (vcpi_installed)
{
link_vcpi(pd,pt); /* Get VCPI Page Table */
for ( i=0; i<1024; i++)
if (pt[i] & PT_P)
pt[i] |= PT_I;
}
else
{
for (i=0; i < DOS_PAGE; i++)
pt[i] = ((unsigned long)i<<12) | PT_P | PT_W | PT_I;
for (; i<1024; i++)
pt[i] = 0;
}
pd[0] =
pd[0x3c0] = far2pte(pt, PT_P | PT_W | PT_I); /* map 1:1 1st Mb */
pd_seg[0] =
pd_seg[0x3c0] = (word32)pt >> 24;
gdt_phys.limit = gdt[g_gdt].lim0;
gdt_phys.base = ptr2linear(&gdt);
idt_phys.limit = gdt[g_idt].lim0;
idt_phys.base = ptr2linear(&idt);
handle_screen_swap(pt);
a_tss.tss_ebx = screen_primary;
a_tss.tss_ebp = screen_secondary;
prog_info.linear_address_of_primary_screen = screen_primary;
prog_info.linear_address_of_secondary_screen = screen_secondary;
/* CB changes: two page tables + stuff for graphics page fault handler */
/* to move around page tables in the page directory */
/* OLD:
* graphics_pt = (word32 far *)((long)valloc(VA_640) << 24);
* graphics_pt_lin = ptr2linear(graphics_pt);
* for (i=0; i<1024; i++)
* graphics_pt[i] = 0x000a0000L | ((i * 4096L) & 0xffffL) | PT_W | PT_U;
* pd[0x380] = far2pte(graphics_pt, PT_P | PT_W | PT_U);
* pd_seg[0x380] = (word32)graphics_pt >> 24;
*/
graphics_pd = &pd[0x380];
graphics_pd_seg = &pd_seg[0x380];
graphics_pd_lin = ptr2linear(graphics_pd);
graphics_pd_seg_lin = ptr2linear(graphics_pd_seg);
graphics_pt1 = (word32 far *)((long)valloc(VA_640) << 24);
graphics_pt2 = (word32 far *)((long)valloc(VA_640) << 24);
graphics_pt1_lin = ptr2linear(graphics_pt1);
graphics_pt2_lin = ptr2linear(graphics_pt2);
graphics_pt1_loc = 0; /* first RW page */
graphics_pt2_loc = (0x03000000L / 4096L / 1024L); /* first page of the 16 MB write only area */
graphics_pd[(word16)graphics_pt1_loc] = far2pte(graphics_pt1,(PT_P | PT_W | PT_U));
graphics_pd[(word16)graphics_pt2_loc] = far2pte(graphics_pt2,(PT_P | PT_W | PT_U));
graphics_pd_seg[(word16)graphics_pt1_loc] = (word32)graphics_pt1 >> 24;
graphics_pd_seg[(word16)graphics_pt2_loc] = (word32)graphics_pt2 >> 24;
for(i = 0; i < 1024; i++) {
graphics_pt1[i] = 0L;
graphics_pt2[i] = 0L;
}
/* end CB changes */
c_tss.tss_cr3 =
a_tss.tss_cr3 =
o_tss.tss_cr3 =
i_tss.tss_cr3 =
p_tss.tss_cr3 =
f_tss.tss_cr3 =
r_tss.tss_cr3 =
v74_tss.tss_cr3 =
v78_tss.tss_cr3 =
v79_tss.tss_cr3 = far2pte(pd, 0);
a_tss.tss_esi = far2pte(pd,0) >> 12; /* PID */
prog_info.pid = far2pte(pd,0) >> 12;
}
else /* use_DPMI */
{
if (areas[A_bss].last_addr < 0x11000L)
areas[A_bss].last_addr = 0x11000L;
handle_screen_swap(NULL);
a_tss.tss_ebx = screen_primary;
a_tss.tss_ebp = screen_secondary;
prog_info.linear_address_of_primary_screen = screen_primary;
prog_info.linear_address_of_secondary_screen = screen_secondary;
a_tss.tss_esi = FP_SEG(paging_buffer);
prog_info.pid = FP_SEG(paging_buffer);
#if VERBOSE
fprintf(stderr,"%ld+%ld+%ld = %ld\n", aouthdr.tsize, aouthdr.dsize, aouthdr.bsize,
aouthdr.tsize+aouthdr.dsize+aouthdr.bsize);
#endif
/* In certain instances, there is a large gap between text and data. If it
is larger than the stack size, lets take advantage of it. */
if (areas[A_data].first_addr - areas[A_text].last_addr <= DPMI_STACK)
{ /* No room, put stack between bss and arena */
areas[A_stack].first_addr = (areas[A_bss].last_addr + 1 + 0xfff) & ~0xfff;
if (areas[A_stack].first_addr < 0x11000L)
areas[A_stack].first_addr = 0x11000L; /* Some bizzare windows bug */
areas[A_stack].last_addr = areas[A_stack].first_addr + DPMI_STACK - 1;
areas[A_arena].first_addr = areas[A_stack].last_addr + 1;
areas[A_arena].last_addr = areas[A_stack].last_addr;
} else { /* Put stack in gap */
areas[A_stack].last_addr = areas[A_data].first_addr - 1;
/* areas[A_stack].first_addr = areas[A_stack].last_addr - DPMI_STACK + 1; */
areas[A_stack].first_addr = (areas[A_text].last_addr + 1 + 0xfff) & ~0xfff;
if (areas[A_stack].first_addr < 0x11000L)
areas[A_stack].first_addr = 0x11000L; /* Some bizzare windows bug */
}
areas[A_vga].first_addr =
areas[A_syms].first_addr =
areas[A_syms2].first_addr = 1; /* Not used */
areas[A_vga].last_addr =
areas[A_syms].last_addr =
areas[A_syms2].last_addr = 0; /* len zero */
/* Here and in changeBreak we use 64K breaks to minimize calls to DPMI */
newbytes = (areas[A_arena].last_addr + 1 + DPMIgetpage) & ~DPMIgetpage;
DPMIprotectedMode();
if (! DPMIalloc(&DPMImem, newbytes))
{
DPMIrealMode();
fprintf(stderr,"DPMI: Not enough memory (0x%08lx bytes).\n", newbytes);
exit(1);
}
DPMIselect = DPMIselector(4);
if (DPMIselect == 0)
{
DPMIrealMode();
fprintf(stderr,"DPMI: Not enough selectors.\n");
exit(1);
}
setDPMISelectors(1);
DPMIassignSelector(DPMIselect+24, 0xc0b3, 0L, 0xfffffL);
DPMIrealMode();
core_selector =
a_tss.tss_gs =
prog_info.selector_for_linear_memory = (word16)(DPMIselect+24);
a_tss.tss_eax = (word32)(DPMIselect + 24) << 16; /* Hi word for "core" selector */
arena_ds = a_tss.tss_ds = a_tss.tss_es = a_tss.tss_fs = DPMIselect;
arena_cs = a_tss.tss_cs = DPMIselect + 8;
a_tss.tss_ss = DPMIselect + 16;
a_tss.tss_esp = areas[A_stack].last_addr + 1;
a_tss.tss_eflags = 0x0202;
r_tss.tss_es = r_tss.tss_fs = DPMIselect;
r_tss.tss_cs = DPMIselect + 8;
loadAout(&areas[A_text]);
loadAout(&areas[A_data]);
Pmemset(DPMIselect, areas[A_bss].first_addr, 0, areas[A_bss].last_addr + 1 - areas[A_bss].first_addr);
Pmemset(DPMIselect, areas[A_arena].first_addr, 0, newbytes - areas[A_arena].first_addr);
close(aout_f);
} /* end else use_DPMI */
#if VERBOSE
for (i=0; i<5; i++)
fprintf(stderr,"%d %-10s %08lx-%08lx (offset 0x%08lx)\n", i, aname[i], areas[i].first_addr, areas[i].last_addr, areas[i].foffset);
#endif
}
static update_status(int c, int col)
{
int r;
r = peek(screen_seg, 2*79);
poke(screen_seg, 2*col, c);
return r;
}
static int cant_ask_for(int32 amount)
{
static word32 reserved = 0;
static word32 used_at_first = 0;
word32 max;
if (use_DPMI)
return 0;
if (used_at_first == 0)
used_at_first = (valloc_used() - dalloc_used()) * 4096L + 8192L /* stack */;
max = valloc_max_size()*4092L - used_at_first; /* 4096 - PTE */
if (reserved + amount >= max)
max += dalloc_max_size() * 4092L;
if (reserved + amount < max)
{
reserved += amount;
return 0;
}
return 1;
}
word32 paging_brk(word32 b)
{
word32 r;
r = (areas[A_arena].last_addr - ARENA + 1 + 7) & ~7; /* Even value */
if (use_DPMI)
if (! changeBreak(b)) return -1L;
if (cant_ask_for(b-r))
return -1L;
areas[A_arena].last_addr = b + ARENA - 1;
return r;
}
word32 paging_sbrk(int32 b)
{
word32 r;
r = (areas[A_arena].last_addr - ARENA + 1 + 7) & ~7; /* Even value */
if (use_DPMI)
if (! changeBreak(r + b)) return -1L;
if (cant_ask_for(b))
return -1L;
areas[A_arena].last_addr = r + b + ARENA - 1;
return r;
}
int page_is_valid(word32 vaddr)
{
int a;
for (a=0; a<MAX_AREA; a++)
if ((vaddr <= areas[a].last_addr) && (vaddr >= areas[a].first_addr))
return 1;
if ( use_DPMI )
return 0;
if (vaddr >= 0xf0000000L)
return 1;
return 0;
}
int page_in(void)
{
int old_status;
TSS *old_util_tss;
word32 far *pt;
word32 vaddr, cnt32;
word32 eaddr, vtran, vcnt, zaddr;
int pdi, pti, pn, a, count;
unsigned dblock;
if (use_DPMI)
return 1;
#if 0
unsigned char buf[100];
sprintf(buf, "0x%08lx", a_tss.tss_cr2 - ARENA);
for (a=0; buf[a]; a++)
poke(screen_seg, 80+a*2, 0x0600 | buf[a]);
#endif
old_util_tss = utils_tss;
utils_tss = &f_tss;
vaddr = tss_ptr->tss_cr2;
for (a=0; a<MAX_AREA; a++)
if ((vaddr <= areas[a].last_addr) && (vaddr >= areas[a].first_addr))
goto got_area;
if (vaddr >= 0xf0000000L)
{
pdi = (word16)(vaddr >> 22) & 0x3ff;
if (!(pd[pdi] & PT_P)) /* put in a mapped page table */
{
pn = valloc(VA_640);
pt = (word32 far *)((word32)pn << 24);
if (pd[pdi] & PT_S)
{
dread(paging_buffer, (word16)(pd[pdi]>>12));
movedata(_DS, FP_OFF(paging_buffer), FP_SEG(pt), FP_OFF(pt), 4096);
dfree((word16)(pd[pdi]>>12));
pd[pdi] = pn2pte(pn, PT_P | PT_W | PT_I | PT_S);
pd_seg[pdi] = pn;
}
else
{
pd[pdi] = pn2pte(pn, PT_P | PT_W | PT_I | PT_S);
pd_seg[pdi] = pn;
vaddr &= 0x0fc00000L;
for (pti = 0; pti < 1024; pti++)
pt[pti] = PT_P | PT_W | PT_I | vaddr | (((word32)pti)<<12);
}
return 0;
}
pt = (word32 far *)((word32)(pd_seg[pdi]) << 24);
vaddr &= 0x0ffff000L;
pti = (word16)(vaddr>>12) & 0x3ff;
pt[pti] = vaddr | PT_P | PT_W | PT_I;
return 0;
}
segfault(tss_ptr->tss_cr2);
return 1;
got_area:
vaddr &= 0xFFFFF000L; /* points to beginning of page */
#if 0 /* handled in protected mode for speed */
if (a == A_vga)
return graphics_fault(vaddr, graphics_pt);
#endif
#if VERBOSE
printf("area(%d) - ", a);
#endif
if ((a == A_bss) & (vaddr < areas[a].first_addr)) /* bss, but data too */
{
#if VERBOSE
printf("split page (data/bss) detected - ");
#endif
a = A_data; /* set to page in data */
}
if (topline_info)
old_status = update_status(achar[a] | 0x0a00, 78);
#if VERBOSE
printf("Paging in %s block for vaddr %#010lx -", aname[a], tss_ptr->tss_cr2-ARENA);
#endif
pdi = (word16)(vaddr >> 22) & 0x3ff;
if (!(pd[pdi] & PT_P)) /* put in an empty page table if required */
{
pn = valloc(VA_640);
pt = (word32 far *)((word32)pn << 24);
if (pd[pdi] & PT_I)
{
dread(paging_buffer, (word16)(pd[pdi]>>12));
movedata(_DS, FP_OFF(paging_buffer), FP_SEG(pt), FP_OFF(pt), 4096);
dfree((word16)(pd[pdi] >> 12));
pd[pdi] = pn2pte(pn, PT_P | PT_W | PT_I | PT_S);
pd_seg[pdi] = pn;
}
else
{
pd[pdi] = pn2pte(pn, PT_P | PT_W | PT_I | PT_S);
pd_seg[pdi] = pn;
for (pti=0; pti<1024; pti++)
pt[pti] = PT_W | PT_S;
}
}
else
pt = (word32 far *)((word32)(pd_seg[pdi]) << 24);
pti = (word16)(vaddr >> 12) & 0x3ff;
if (pt[pti] & PT_P)
{
utils_tss = old_util_tss;
if (topline_info)
update_status(old_status, 78);
return 0;
}
count = MAX_PAGING_NUM;
if (count > mem_avail/4)
count = 1;
if (pti + count > 1024)
count = 1024 - pti;
if (vaddr + count*4096L > areas[a].last_addr+4096L)
count = (word16)((areas[a].last_addr - vaddr + 4095) / 4096);
if (count < 1)
count = 1;
zaddr = eaddr = -1;
vtran = vaddr;
vcnt = 0;
for (; count; count--, pti++, vaddr+=4096)
{
if (pt[pti] & PT_P)
break;
if (eaddr != -1 && (pt[pti] & PT_I) != 0)
break; /* EastWind 1993 */
dblock = (word16)(pt[pti] >> 12);
pn = valloc(VA_1M);
pt[pti] &= 0xfffL & ~(word32)(PT_A | PT_D);
pt[pti] |= ((word32)pn << 12) | PT_P;
if (pt[pti] & PT_I)
{
#if VERBOSE
printf(" swap");
#endif
dread(paging_buffer, dblock);
dfree(dblock);
memput(vaddr, paging_buffer, 4096);
pt[pti] &= ~(word32)(PT_A | PT_D); /* clean dirty an accessed bits (set by memput) */
}
else
{
pt[pti] &= ~(word32)(PT_C);
if (areas[a].foffset != -1)
{
#if VERBOSE
if (a == A_emu)
printf(" emu");
else
printf(" exec");
#endif
if (eaddr == -1)
{
eaddr = areas[a].foffset + (vaddr - areas[a].first_addr);
vtran = vaddr;
}
cnt32 = areas[a].last_addr - vaddr + 1;
if (cnt32 > 4096)
cnt32 = 4096;
else
zaddr = vaddr;
vcnt += cnt32;
}
else
{
zero32(vaddr);
#if VERBOSE
printf(" zero");
#endif
}
pt[pti] |= PT_I;
}
/* if (paged_out_something) */
break;
}
if (eaddr != -1)
{
int cur_f, rsize, vc;
cur_f = areas[a].fileno;
lseek(cur_f, eaddr, 0);
rsize = read(cur_f, paging_buffer, (word16)vcnt);
if (rsize < vcnt)
memset(paging_buffer+rsize, 0, (word16)(vcnt-rsize));
if (zaddr != -1)
zero32(zaddr);
memput(vtran, paging_buffer, vcnt);
vc = (word16)(vcnt / 4096); /* don't reset BSS parts */
while (vc)
{
pdi = (word16)(vtran >> 22);
pt = (word32 far *)((word32)(pd_seg[pdi]) << 24);
pti = (word16)(vtran >> 12) & 0x3ff;
pt[pti] &= ~(word32)(PT_A | PT_D); /* clean dirty an accessed bits (set by memput) */
vc--;
vtran += 4096;
}
}
#if VERBOSE
printf("\n");
#endif
utils_tss = old_util_tss;
if (topline_info)
update_status(old_status, 78);
return 0;
}
static fInPageOutEverything = 0;
static last_po_pdi = 0;
static last_po_pti = 0;
static last_pti = 0;
unsigned page_out(int where) /* return >= 0 page which is paged out, 0xffff if not */
{
int start_pdi, start_pti, pti;
word32 far *pt, v, rv;
unsigned dblock;
int old_status;
if (topline_info)
{
old_status = update_status('>' | 0x0a00, 79);
}
start_pdi = last_po_pdi;
start_pti = last_po_pti;
if (where == VA_640)
{
for (pti = last_pti+1; pti != last_pti; pti = (pti+1)%1024)
if ((pd[pti] & (PT_P | PT_S)) == (PT_P | PT_S))
{
dblock = dalloc();
movedata(pd_seg[pti]<<8, 0, _DS, FP_OFF(paging_buffer), 4096);
dwrite(paging_buffer, dblock);
#if VERBOSE
printf ("out_640 %d\n", pti);
#endif
pd[pti] &= 0xfff & ~(word32)(PT_P); /* no longer present */
pd[pti] |= (long)dblock << 12;
if (topline_info)
update_status(old_status, 79);
last_pti = pti;
return pd_seg[pti];
}
return -1;
}
pt = (word32 far *)((word32)(pd_seg[last_po_pdi]) << 24);
do {
if ((pd[last_po_pdi] & (PT_P | PT_S)) == (PT_P | PT_S))
{
if ((pt[last_po_pti] & (PT_P | PT_S)) == (PT_P | PT_S))
{
rv = pt[last_po_pti] >> 12;
v = ((word32)last_po_pdi << 22) | ((word32)last_po_pti << 12);
if (!fInPageOutEverything)
if ((v & 0xfffff000L) == ((tss_ptr->tss_eip + ARENA) & 0xfffff000L) ||
(v & 0xfffff000L) == ((tss_ptr->tss_esp + ARENA) & 0xfffff000L))
{
#if VERBOSE
printf("\nskip: v=%08lx - ", v);
#endif
goto bad_choice;
}
if (pt[last_po_pti] & (PT_C | PT_D))
{
pt[last_po_pti] |= PT_C;
dblock = dalloc();
memget(v, paging_buffer, 4096);
#if VERBOSE
printf ("dout %08lx", ((word32)last_po_pdi<<22) | ((word32)last_po_pti<<12));
#endif
dwrite(paging_buffer, dblock);
pt[last_po_pti] &= 0xfff & ~PT_P; /* no longer present */
pt[last_po_pti] |= (long)dblock << 12;
}
else
{
pt[last_po_pti] = PT_W | PT_S;
#if VERBOSE
printf ("dflush %08lx", ((word32)last_po_pdi<<22) | ((word32)last_po_pti<<12));
#endif
}
if (topline_info)
update_status(old_status, 79);
return (word16)rv;
}
}
else /* imagine we just checked the last entry */
last_po_pti = 1023;
bad_choice:
if (++last_po_pti == 1024)
{
last_po_pti = 0;
if (++last_po_pdi == 1024)
last_po_pdi = 0;
pt = (word32 far *)((word32)(pd_seg[last_po_pdi]) << 24);
}
} while ((start_pdi != last_po_pdi) || (start_pti != last_po_pti));
if (topline_info)
update_status(old_status, 79);
return 0xffff;
}
unsigned pd_dblock;
extern int valloc_initted;
extern void vfree_640(void);
extern void vrecover_640(void);
void page_out_everything(void)
{
int pdi, i;
word32 opde;
unsigned ptb;
void far *fp;
if(use_DPMI)
{
saveDPMIstate();
return;
}
fInPageOutEverything = 1;
#ifndef KEEP_ON_EXEC
while (page_out(-1) != 0xffff)
{
vfree();
}
#endif
for (pdi=0; pdi<1024; pdi++)
if (pd[pdi] & PT_P)
{
ptb = dalloc();
opde = pd[pdi] & 0xfffff001L;
fp = (word32 far *)((word32)pd_seg[pdi] << 24);
movedata(FP_SEG(fp), FP_OFF(fp), _DS, FP_OFF(paging_buffer), 4096);
dwrite(paging_buffer, ptb);
vfree();
pd[pdi] = (pd[pdi] & (0xFFF&~PT_P)) | ((word32)ptb<<12);
for (i=pdi+1; i<1024; i++)
if ((pd[i] & 0xfffff001L) == opde)
pd[i] = pd[pdi];
}
movedata(FP_SEG(pd), FP_OFF(pd), _DS, FP_OFF(paging_buffer), 4096);
pd_dblock = dalloc();
dwrite(paging_buffer, pd_dblock);
vfree();
#ifndef KEEP_ON_EXEC
vcpi_flush();
valloc_uninit();
#else
vfree_640();
#endif
}
void page_in_everything(void)
{
int pdi, i;
word32 opde;
unsigned ptb;
word32 far *pt;
unsigned pta;
if(use_DPMI)
{
restoreDPMIstate();
return;
}
fInPageOutEverything = 0;
#ifndef KEEP_ON_EXEC
valloc_initted = 0;
#else
vrecover_640();
#endif
pta = valloc(VA_640);
pd = (word32 far *)((word32)pta << 24);
dread(paging_buffer, pd_dblock);
dfree(pd_dblock);
movedata(_DS, FP_OFF(paging_buffer), FP_SEG(pd), FP_OFF(pd), 4096);
for (pdi=0; pdi<1024; pdi++)
if (pd[pdi] && !(pd[pdi] & PT_P))
{
pta = valloc(VA_640);
opde = pd[pdi] & 0xfffff001L;
pt = (word32 far *)((word32)pta << 24);
ptb = (word16)(opde >> 12);
dread(paging_buffer, ptb);
dfree(ptb);
movedata(_DS, FP_OFF(paging_buffer), FP_SEG(pt), FP_OFF(pt), 4096);
if (pdi == 0)
vcpi_pt = (word32 far *)((word32)pta << 24);
pd[pdi] = pn2pte(pta, (pd[pdi] & 0xFFF) | PT_P);
pd_seg[pdi] = pta;
for (i=pdi+1; i<1024; i++)
if ((pd[i] & 0xfffff001L) == opde)
{
pd[i] = pd[pdi];
pd_seg[i] = pd_seg[pdi];
}
}
/* CB changes: two tables + page directory stuff */
/* OLD:
* graphics_pt = (word32 far *)((long)pd_seg[0x380] << 24);
* graphics_pt_lin = ptr2linear(graphics_pt);
*/
graphics_pd = &pd[0x380];
graphics_pd_lin = ptr2linear(graphics_pd);
graphics_pt1 = (word32 far *)((word32)graphics_pd_seg[(word16)graphics_pt1_loc] << 24);
graphics_pt2 = (word32 far *)((word32)graphics_pd_seg[(word16)graphics_pt2_loc] << 24);
graphics_pt1_lin = ptr2linear(graphics_pt1);
graphics_pt2_lin = ptr2linear(graphics_pt2);
for(i = 0; i < 1024; i++) {
graphics_pt1[i] = 0L;
graphics_pt2[i] = 0L;
}
/* end CB changes */
}
static word32 emu_start_ip_val = 0;
word32 emu_start_ip()
{
return emu_start_ip_val;
}
int emu_install(char *filename)
{
FILEHDR filehdr;
AOUTHDR aouthdr;
GNU_AOUT gnu_aout;
int emu_f;
areas[A_emu].first_addr = EMU_TEXT+ARENA;
areas[A_emu].last_addr = EMU_TEXT-1+ARENA;
areas[A_emu].foffset = 0;
if (use_DPMI)
return 0;
if (filename == 0)
return 0;
emu_f = open(filename, O_RDONLY|O_BINARY);
if (emu_f < 0)
{
fprintf(stderr, "Can't open 80387 emulator file <%s>\n", filename);
return 0;
}
areas[A_emu].fileno = emu_f;
read(emu_f, &filehdr, sizeof(filehdr));
if (filehdr.f_magic != 0x14c)
{
lseek(emu_f, 0L, 0);
read(emu_f, &gnu_aout, sizeof(gnu_aout));
emu_start_ip_val = gnu_aout.entry;
aouthdr.tsize = gnu_aout.tsize;
aouthdr.dsize = gnu_aout.dsize;
aouthdr.bsize = gnu_aout.bsize;
}
else
{
read(emu_f, &aouthdr, sizeof(aouthdr));
emu_start_ip_val = aouthdr.entry;
}
areas[A_emu].last_addr += aouthdr.tsize + aouthdr.dsize + aouthdr.bsize + (emu_start_ip_val & 0xff);
return 1;
}
word32 stack_used(void)
{
int pdi,pti;
word32 far *pt;
for(pdi=0x140;pdi<0x240;pdi++)
if( pd[pdi] & PT_I ) { /* really should check for PT_P here, but */
pt = (word32 far *)((word32)(pd_seg[pdi]) << 24);
for(pti=0;pti<1024;pti++)
if( pt[pti] & PT_I )
return ((word32)(0x23f-pdi) << 22) | ((word32)(1024-pti) << 12);
}
return 0L; /* No stack pd entries found! */
}